package com.geo.geotool.util.file;

import info.monitorenter.cpdetector.io.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;

@Slf4j
@Component
public class CpdetectorEncoding {
    public Charset getEncoding(InputStream buffIn, boolean isFast) throws IOException {
        return getEncoding(buffIn,buffIn.available(),isFast);
    }

    public Charset getFastEncoding(InputStream buffIn) throws IOException{
        return getEncoding(buffIn,MAX_READBYTE_FAST,DEFALUT_DETECT_STRATEGY);
    }

    public Charset getEncoding(InputStream in, int size, boolean isFast) throws IOException {
        try {
            Charset charset = null;
            int tmpSize = in.available();
            size = size >tmpSize?tmpSize:size;
            //if in support mark method,
            if(in.markSupported()){
                if(isFast){
                    size = size>MAX_READBYTE_FAST?MAX_READBYTE_FAST:size;
                    in.mark(size++);
                    charset = getFastDetector().detectCodepage(in, size);
                }else{
                    in.mark(size++);
                    charset = getDetector().detectCodepage(in, size);
                }
                in.reset();
            }else{
                if(isFast){
                    size = size>MAX_READBYTE_FAST?MAX_READBYTE_FAST:size;
                    charset = getFastDetector().detectCodepage(in, size);
                }else{
                    charset = getDetector().detectCodepage(in, size);
                }
            }
            return charset;
        }catch(IllegalArgumentException e){
            log.error(e.getMessage(),e);
            throw e;
        } catch (IOException e) {
            log.error(e.getMessage(),e);
            throw e;
        }

    }


    public Charset getEncoding(byte[] byteArr,boolean isFast) throws IOException{
        return getEncoding(byteArr, byteArr.length, isFast);
    }


    public Charset getFastEncoding(byte[] byteArr) throws IOException{
        return getEncoding(byteArr, MAX_READBYTE_FAST, DEFALUT_DETECT_STRATEGY);
    }


    public Charset getEncoding(byte[] byteArr, int size,boolean isFast) throws IOException {
        size = byteArr.length>size?size:byteArr.length;
        if(isFast){
            size = size>MAX_READBYTE_FAST?MAX_READBYTE_FAST:size;
        }
        ByteArrayInputStream byteArrIn = new ByteArrayInputStream(byteArr,0,size);
        BufferedInputStream in = new BufferedInputStream(byteArrIn);
        try {
            Charset charset = null;
            if(isFast){
                charset = getFastDetector().detectCodepage(in, size);
            }else{
                charset = getDetector().detectCodepage(in, size);
            }
            return charset;
        } catch (IllegalArgumentException e) {
            log.error(e.getMessage(),e);
            throw e;
        } catch (IOException e) {
            log.error(e.getMessage(),e);
            throw e;
        }

    }

    private static CodepageDetectorProxy detector =null;
    private static CodepageDetectorProxy fastDtector =null;
    private static ParsingDetector parsingDetector =  new ParsingDetector(false);
    private static ByteOrderMarkDetector byteOrderMarkDetector = new ByteOrderMarkDetector();

    //default strategy use fastDtector
    private static final boolean DEFALUT_DETECT_STRATEGY = true;

    private static final int MAX_READBYTE_FAST = 8;

    private static CodepageDetectorProxy getDetector(){

        if(detector==null){
            detector = CodepageDetectorProxy.getInstance();
            // Add the implementations of info.monitorenter.cpdetector.io.ICodepageDetector:
            // This one is quick if we deal with unicode codepages:
            detector.add(byteOrderMarkDetector);
            // The first instance delegated to tries to detect the meta charset attribut in html pages.
            detector.add(parsingDetector);
            // This one does the tricks of exclusion and frequency detection, if first implementation is
            // unsuccessful:
            detector.add(JChardetFacade.getInstance());
            detector.add(ASCIIDetector.getInstance());
        }

        return detector;
    }


    private static CodepageDetectorProxy getFastDetector(){
        if(fastDtector==null){
            fastDtector = CodepageDetectorProxy.getInstance();
            fastDtector.add(UnicodeDetector.getInstance());
            fastDtector.add(byteOrderMarkDetector);
            fastDtector.add(JChardetFacade.getInstance());
            fastDtector.add(ASCIIDetector.getInstance());
        }
        return fastDtector;
    }
}
